package com.heiketu.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

/**
 * 用于配置spring security的配置类
 */
@Configuration
// 用于开启方法授权中@secured、@PreAuthorize、@PostAuthorize注解
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 大部分spring security相关的配置都是在该方法中配置的
     * spring security是从上往下进行匹配，所以一旦匹配到，则不会往下执行。所以大范围的最好放在最下面。
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // http.csrf().disable() 默认情况下spring security在登录、退出时采用的是post请求方式，而默认情况下，spring security建议带上csrf请求域，
        // 防止跨域请求伪造攻击。
        http.authorizeRequests()
                //.antMatchers("/r/p1").hasAnyAuthority("p1")
                //.antMatchers("/r/p2").hasAnyAuthority("p2")
                .antMatchers("/r/**")
                .authenticated() // 需要进行认证后才能访问
                .anyRequest() // 之后任意的请求
                .permitAll() // 允许通过
                .and().formLogin() // 表示允许表单提交(没设置前，spring security会默认提供一个login登录页面)
                .loginPage("/loginPage") // 自定义自己的登录页面
                .loginProcessingUrl("/admin/submit") // 登录处理的url路径
                .successForwardUrl("/success") // 登录成功后跳转到的目标页面
                .and()
                .sessionManagement() // session管理的方式(如何创建：分别为三种策略: ALWAYS(如果没有session存在就创建一个)
                // | IfRequired(如何需要就创建一个session(默认)登录时)
                // | never(SpringSecurity将不会创建session，但是如何应用中其他地方创建了session，
                // 那么spring security将会使用它)
                // | stateless(spring security 将绝对不会创建session，也不使用session)) ----> 在分布式下使用token保存用户信息
                // ，所以完全可以不使用session
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                .and().logout().logoutSuccessUrl("/login‐view?logout")
                // 默认情况下logout是post请求，如果在开启csrf下，可以使用get请求的方式进行退出操作.
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"));
    }
}
